/**
 Brainfuck-Robots Bluetooth App
 Copyright (C) <2014>  <Simon Grafenhorst>

 This file is part of the Brainfuck-Robots Bluetooth App.

 The Brainfuck-Robots Bluetooth App is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 The Brainfuck-Robots Bluetooth App is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with the Brainfuck-Robots Bluetooth App.  If not, see <http://www.gnu.org/licenses/>.
 */
package de.brainfuckrobots.bluetooth;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import android.bluetooth.BluetoothSocket;
import android.os.AsyncTask;
import android.util.Log;
import android.widget.TextView;
import android.widget.Toast;

public class CommunicationThread extends AsyncTask<Void, byte[], Void> {

    private BluetoothSocket socket;
    private InputStream inputStream;
    private OutputStream outputStream;
    private String tag = "CommunicationThread";
    private byte[] in;
    private ControllingView controllingView;
    private byte[] out;
    private boolean shoot = false;
    private ScheduledThreadPoolExecutor executor;
    private long timestamp;
    private static long shootingTimespan = 3000;

    public void setShoot(boolean shoot){
        this.shoot = shoot;
    }

    public CommunicationThread(BluetoothSocket socket) {
        super();
        out = new byte[2];
        in = new byte[2];
        timestamp = System.currentTimeMillis();
        this.socket = socket;
        controllingView = (ControllingView) MainActivity.getContext().findViewById(R.id.controllingView);

    }

    public void observe() {
        Runnable update = new Runnable() {
            @Override
            public void run() {
                out[0] = (byte)((float)controllingView.getAngle() / 360f * 255f);
                out[0] &= 254;
                out[1] = (byte)controllingView.getSpeed();
                out[1] %= 128;
                out[1] |= 1 << 0;
                if(shoot){
                    if(System.currentTimeMillis() - timestamp > shootingTimespan){
                        out[1] |= 1 << 7;
                        timestamp = System.currentTimeMillis();
                        Log.i(tag, "Shoot; timed");
                    }
                    shoot = false;
                }
                write(out);
            }
        };
        executor = new ScheduledThreadPoolExecutor(50);
        executor.scheduleAtFixedRate(update, 50, 10, TimeUnit.MILLISECONDS);
    }

    public void write(byte[] bytes) {
        try {
            outputStream.write(bytes);
            outputStream.flush();
        } catch (IOException e) {
            Log.e(tag, "Could not write bytes");
            cancel();
        }
    }

    public void cancel() {
        try {
            executor.shutdown();
            socket.close();
            MainActivity.getContext().discover(null);
        } catch (IOException e) {
        }
    }

    @Override
    protected Void doInBackground(Void... params) {
        byte[] buffer = new byte[1];
        observe();

        try {
            inputStream = socket.getInputStream();
            outputStream = socket.getOutputStream();
        } catch (IOException e) {
            Log.e(tag, "Could not get the input / output stream of the socket");
        }
        int receivedBytes = 0;
        while (true) {
            try {
                inputStream.read(buffer);
                //Publishing the input if both bytes are received
                if (receivedBytes == 2) {
                    publishProgress(in);
                    in = new byte[2];
                    receivedBytes = 0;
                } else {
                    in[receivedBytes] = buffer[0];
                    receivedBytes++;
                }
            } catch (IOException e) {
                break;
            }
        }
        return null;
    }

    @Override
    protected void onProgressUpdate(byte[]... values) {
        /*((TextView) MainActivity.getContext().findViewById(R.id.console))
                .setText(toBinary(values[0][1]));
        */
        //Replying on receiving
        /*
        String ok = "OK";
		write(ok.getBytes());
		*/
    }

    private String toBinary( byte byt )
    {
        StringBuilder sb = new StringBuilder(Byte.SIZE);
        for( int i = 0; i < Byte.SIZE; i++ )
            sb.append((byt << i % Byte.SIZE & 0x80) == 0 ? '0' : '1');
        return sb.toString();
    }

}
